--[[ 怒首领蜂1代脚本,作用是显示坐标和在坐标位置显示一个红色方块
  可作为cave stg游戏的模版
  
  其实使用最简单的read_u16*4/256再四舍五入就行了...
  
  目前使用的是2p数据,2p的颜色似乎更适合中心红点得分也略高
  本游戏自身机体就很清楚,所以注释掉了画十字的代码,红点也用了半透明大概
  能看到就行,不透明感觉视觉效果更差.
  
  测试后决定使用十字线显示
  
  更新使用MyMame模块,轻度防错
  
  By setycyas @2025-02-11
]]

--防止重运行,需用用_G,用重复require不行,因为F4重启可能会把脚本加载到全新模块与原来的不共通
if (_G.game) then
  print('script already loaded!')
  return
end

local myMame = require('MyMame')

-- 这里设定基本参数
GAME = {
  -- 游戏名,防重加载用
  NAME = "ddonpach_autoboot",
  -- 分辨率
  X_RESOLUTION = 240,
  Y_RESOLUTION = 320,
  -- 横坐标纵坐标内存地址
  --[[ 1p
  X_ADDR_HIGH = 0x102C94,
  X_ADDR_LOW = 0x102C95,
  Y_ADDR_HIGH = 0x102C92,
  Y_ADDR_LOW = 0x102C93,
  ]]
  --2p 2p不挂命天上小星星过关不重置,得分更高
  X_ADDR_HIGH = 0x102CD4,
  X_ADDR_LOW = 0x102CD5,
  Y_ADDR_HIGH = 0x102CD2,
  Y_ADDR_LOW = 0x102CD3,
  -- 如果仅用read_u16读取坐标和计算,就设定为true
  USE_U16 = true,
  --散枪和激光火力等级地址
  --[[1p
  SHOT_ADDR = 102CAD
  LASER_ADDR = 102CAF
  ]]
  --2p
  SHOT_ADDR = 0x102CED,
  LASER_ADDR = 0x102CEF,
  -- 坐标最终修正比例
  X_OFFSET = 0.0,
  Y_OFFSET = 0.0,
  -- 自己中心方块的半长半高,单位为MAME的屏幕比例
  BOX_HALF_WIDTH = 0.005,
  BOX_HALF_HEIGHT = 0.005,
  -- 两个十字方块的半长半高
  XBOX_HALF_WIDTH = 0.032,
  XBOX_HALF_HEIGHT = 0.0065,
  YBOX_HALF_WIDTH = 0.0065,
  YBOX_HALF_HEIGHT = 0.035,
  -- 中心方块的边框颜色和中心颜色
  BOX_BORDER_COLOR = 0x88ff0000,
  BOX_COLOR = 0x88ff0000,
  -- 十字方块的边框颜色和中心颜色
  CROSS_BORDER_COLOR = 0x99ff00ff,
  CROSS_COLOR =  0x660000ff,
  -- 十字线颜色,易被自机子弹遮盖,建议设为子弹的反色
  CROSS_LINE_WIDTH = 0.002, --十字线宽度
  CROSS_LINE_COLOR = 0xFFffff00,
  -- mame api用的对象
  mem = manager.machine.devices[':maincpu'].spaces['program'],
  container = manager.machine.screens[":screen.0"].container,
  ui_container = manager.machine.render.ui_container,
}
-- 更新模块设置
myMame.gameName = GAME.NAME
myMame.screenIndex = ':screen.0'

-- 刷新设备,成功获取设备返回true,否返回false
function GAME.refreshDevices()
  GAME.mem = manager.machine.devices[':maincpu'].spaces['program']
  GAME.container = manager.machine.screens[":screen.0"].container
  GAME.ui_container = manager.machine.render.ui_container
  
  if (GAME.mem and GAME.container and GAME.ui_container) then
    return true
  else
    return false
  end
end

-- 坐标变换,从内存坐标变为屏幕显示位置,返回0.0-1.0的浮点数,
function GAME.getX_u16()
  local x
  --实际像素位置就是x的4倍可能四舍五入!最后计算屏幕比例才除以分辨率!
  x = 4.0*GAME.mem:read_u16(GAME.X_ADDR_HIGH)/0x100 
  result = (math.floor(x)+GAME.X_OFFSET)/(GAME.X_RESOLUTION) 
  
  return result
end
function GAME.getY_u16()
  local y
  --实际像素位置就是y的4倍可能四舍五入!最后计算屏幕比例才除以分辨率!
  y = 4.0*GAME.mem:read_u16(GAME.Y_ADDR_HIGH)/0x100
 
  result = (math.floor(y)+GAME.Y_OFFSET)/(GAME.Y_RESOLUTION) 
  
  return result
end
function GAME.getX_u8()
  local xhigh, xlow, result
  xhigh = GAME.mem:read_u8(GAME.X_ADDR_HIGH)
  xlow = GAME.mem:read_u8(GAME.X_ADDR_LOW)
  result = xhigh/60.0 -- 60=240/4
  
  if (xlow > 200) then
    xlow = 200
  end
  if (xlow > 0) then
    result = result+(xlow-56)/11520.0 -- 11520=48*240
  end
  
  return result
end
function GAME.getY_u8()
  local ylow, yhigh, result
  ylow = GAME.mem:read_u8(GAME.Y_ADDR_LOW)
  yhigh = GAME.mem:read_u8(GAME.Y_ADDR_HIGH)
  result = yhigh/80.0 -- 80=320/4
  
  result = result+ylow/15360.0 -- 15360.0=48*320
  return result
end

-- 数据显示,指定位置和颜色,然后是可变的多个显示数据
function GAME.showInfo(position, color, ...)
  local count = select("#", ...)
  
  for i = 1, count do
    local arg = select(i, ...)
    GAME.ui_container:draw_text(position, 1.01-0.05*i, arg, color, 0xFF839496)
  end
  
end

-- 监视数据显示
function GAME.check()
  local shotLv, laserLv --内存数据
  shotLv = GAME.mem:read_u8(GAME.SHOT_ADDR)
  laserLv = GAME.mem:read_u8(GAME.LASER_ADDR)
  -- 显示当前火力等级
  GAME.showInfo(0.05, 0xFF000000, 
    string.format(" SHOT=%d LASER=%d ", shotLv, laserLv)
  )
end

-- 显示自机的几个方框,xfloat,yfloat是浮点数坐标
-- 显示中心
function GAME.showCenter(xfloat, yfloat)

  GAME.container:draw_box(
    yfloat-GAME.BOX_HALF_HEIGHT,
    xfloat-GAME.BOX_HALF_WIDTH,
    yfloat+GAME.BOX_HALF_HEIGHT,
    xfloat+GAME.BOX_HALF_WIDTH,
    GAME.BOX_BORDER_COLOR, GAME.BOX_COLOR
  )
  
end
-- 显示十字方框
function GAME.showCrossBox(xfloat, yfloat)
  -- 横向框
  GAME.container:draw_box(
    yfloat-GAME.XBOX_HALF_HEIGHT,
    xfloat-GAME.XBOX_HALF_WIDTH,
    yfloat+GAME.XBOX_HALF_HEIGHT,
    xfloat+GAME.XBOX_HALF_WIDTH,
    GAME.CROSS_BORDER_COLOR, GAME.CROSS_COLOR
  )
  -- 竖向框
  GAME.container:draw_box(
    yfloat-GAME.YBOX_HALF_HEIGHT,
    xfloat-GAME.YBOX_HALF_WIDTH,
    yfloat+GAME.YBOX_HALF_HEIGHT,
    xfloat+GAME.YBOX_HALF_WIDTH,
    GAME.CROSS_BORDER_COLOR, GAME.CROSS_COLOR
  )
  
end
-- 显示十字线
function GAME.showCrossLine(xfloat, yfloat)

  -- 横线
  GAME.container:draw_box(
    0.0, xfloat-GAME.CROSS_LINE_WIDTH, 
    1.0, xfloat+GAME.CROSS_LINE_WIDTH, 
    GAME.CROSS_LINE_COLOR, GAME.CROSS_LINE_COLOR
  )
  -- 竖线
  GAME.container:draw_box(
    yfloat-GAME.CROSS_LINE_WIDTH, 0.0,
    yfloat+GAME.CROSS_LINE_WIDTH, 1.0,
    GAME.CROSS_LINE_COLOR, GAME.CROSS_LINE_COLOR
  )
  
end

--[[ **************************
  主函数,绑定后每一帧执行一次该函数
]]
function GAME.Main()
  --local xhigh, xlow, yhigh, ylow, shotLv, laserLv --内存数据
  local xfloat, yfloat -- 最终浮点数坐标

  -- 刷新设备,并判断当前帧能否操作
  if (not GAME.refreshDevices()) then
    return
  end

  -- 内存数据读取
  --[[
  xhigh = GAME.mem:read_u8(GAME.X_ADDR_HIGH)
  xlow = GAME.mem:read_u8(GAME.X_ADDR_LOW)
  ylow = GAME.mem:read_u8(GAME.Y_ADDR_LOW)
  yhigh = GAME.mem:read_u8(GAME.Y_ADDR_HIGH)
  shotLv = GAME.mem:read_u8(GAME.SHOT_ADDR)
  laserLv = GAME.mem:read_u8(GAME.LASER_ADDR)
  ]]
  -- 获取自己屏幕坐标
  if GAME.USE_U16 then
    xfloat = GAME.getX_u16()
    yfloat = GAME.getY_u16()
  else
    xfloat = GAME.getX_u8()
    yfloat = GAME.getY_u8()
  end
  
  -- 数据监视
  GAME.check()
  -- 显示角色中心辅助线
  if (xfloat > 0.0) and (yfloat > 0.0) then
    -- 十字线
    GAME.showCrossLine(xfloat, yfloat)
    --十字方框
    --GAME.showCrossBox(xfloat, yfloat)
    -- 中心
    GAME.showCenter(xfloat, yfloat)
  end
  
end

--[[运行]]

-- 刷新api接口
GAME.refreshDevices()
-- 导出到全局变量
_G.game = GAME
-- 绑定每一帧执行的函数,测试时绑定到debug
--myMame.debugRunPerFrame(GAME.Main, 'ddonpach')
myMame.runPerFrame(GAME.Main, 'ddonpach')


return GAME
